using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using CollabApp.Domain.Entities;
using CollabApp.Domain.Repositories;
using CollabApp.Infrastructure.Data;

namespace CollabApp.Infrastructure.Repositories;

/// <summary>
/// 通用仓储实现
/// 提供基本的增删改查、条件查询、分页查询等功能的具体实现
/// </summary>
/// <typeparam name="T">实体类型，必须继承BaseEntity</typeparam>
public class GenericRepository<T> : IRepository<T> where T : BaseEntity
{
    protected readonly ApplicationDbContext _context;
    protected readonly DbSet<T> _dbSet;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="context">数据库上下文</param>
    public GenericRepository(ApplicationDbContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
        _dbSet = _context.Set<T>();
    }

    // ============ 查询操作 ============
    
    /// <summary>
    /// 根据ID查询实体
    /// </summary>
    /// <param name="id">实体ID</param>
    /// <returns>实体，如果不存在则返回null</returns>
    public virtual async Task<T?> GetByIdAsync(Guid id)
    {
        return await _dbSet
            .Where(e => !e.IsDeleted)
            .FirstOrDefaultAsync(e => e.Id == id);
    }

    /// <summary>
    /// 获取所有实体
    /// </summary>
    /// <returns>所有实体集合</returns>
    public virtual async Task<IEnumerable<T>> GetAllAsync()
    {
        return await _dbSet
            .Where(e => !e.IsDeleted)
            .ToListAsync();
    }

    /// <summary>
    /// 根据条件查询单个实体
    /// </summary>
    /// <param name="predicate">查询条件</param>
    /// <returns>符合条件的第一个实体，如果不存在则返回null</returns>
    public virtual async Task<T?> GetSingleAsync(Expression<Func<T, bool>> predicate)
    {
        return await _dbSet
            .Where(e => !e.IsDeleted)
            .Where(predicate)
            .FirstOrDefaultAsync();
    }

    /// <summary>
    /// 根据条件查询多个实体
    /// </summary>
    /// <param name="predicate">查询条件</param>
    /// <returns>符合条件的实体集合</returns>
    public virtual async Task<IEnumerable<T>> GetManyAsync(Expression<Func<T, bool>> predicate)
    {
        return await _dbSet
            .Where(e => !e.IsDeleted)
            .Where(predicate)
            .ToListAsync();
    }

    /// <summary>
    /// 分页查询数据
    /// </summary>
    /// <param name="predicate">查询条件表达式</param>
    /// <param name="pageIndex">页码（从0开始）</param>
    /// <param name="pageSize">每页数据量</param>
    /// <returns>返回分页后的数据集合和总数</returns>
    public virtual async Task<(IEnumerable<T> Items, int TotalCount)> GetPagedAsync(
        Expression<Func<T, bool>> predicate,
        int pageIndex,
        int pageSize)
    {
        if (pageIndex < 0)
            throw new ArgumentException("页码不能小于0", nameof(pageIndex));
        if (pageSize <= 0)
            throw new ArgumentException("每页数据量必须大于0", nameof(pageSize));

        var query = _dbSet
            .Where(e => !e.IsDeleted)
            .Where(predicate);

        var totalCount = await query.CountAsync();
        
        var items = await query
            .Skip(pageIndex * pageSize)
            .Take(pageSize)
            .ToListAsync();

        return (items, totalCount);
    }

    /// <summary>
    /// 分页查询所有数据
    /// </summary>
    /// <param name="pageIndex">页码（从0开始）</param>
    /// <param name="pageSize">每页数据量</param>
    /// <returns>返回分页后的数据集合和总数</returns>
    public virtual async Task<(IEnumerable<T> Items, int TotalCount)> GetPagedAsync(
        int pageIndex,
        int pageSize)
    {
        if (pageIndex < 0)
            throw new ArgumentException("页码不能小于0", nameof(pageIndex));
        if (pageSize <= 0)
            throw new ArgumentException("每页数据量必须大于0", nameof(pageSize));

        var query = _dbSet.Where(e => !e.IsDeleted);

        var totalCount = await query.CountAsync();
        
        var items = await query
            .Skip(pageIndex * pageSize)
            .Take(pageSize)
            .ToListAsync();

        return (items, totalCount);
    }

    /// <summary>
    /// 检查是否存在符合条件的实体
    /// </summary>
    /// <param name="predicate">查询条件</param>
    /// <returns>是否存在</returns>
    public virtual async Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate)
    {
        return await _dbSet
            .Where(e => !e.IsDeleted)
            .AnyAsync(predicate);
    }

    /// <summary>
    /// 根据条件获取数据条数
    /// </summary>
    /// <param name="predicate">查询条件表达式</param>
    /// <returns>返回符合条件的数据条数</returns>
    public virtual async Task<int> CountAsync(Expression<Func<T, bool>> predicate)
    {
        return await _dbSet
            .Where(e => !e.IsDeleted)
            .CountAsync(predicate);
    }

    /// <summary>
    /// 获取所有数据的总数
    /// </summary>
    /// <returns>返回所有数据的总条数</returns>
    public virtual async Task<int> CountAllAsync()
    {
        return await _dbSet
            .Where(e => !e.IsDeleted)
            .CountAsync();
    }

    // ============ 高级查询操作 ============

    /// <summary>
    /// 根据条件查询并排序
    /// </summary>
    /// <typeparam name="TKey">排序字段类型</typeparam>
    /// <param name="predicate">查询条件</param>
    /// <param name="orderBy">排序表达式</param>
    /// <param name="ascending">是否升序，默认true</param>
    /// <returns>排序后的实体集合</returns>
    public virtual async Task<IEnumerable<T>> GetOrderedAsync<TKey>(
        Expression<Func<T, bool>> predicate,
        Expression<Func<T, TKey>> orderBy,
        bool ascending = true)
    {
        var query = _dbSet
            .Where(e => !e.IsDeleted)
            .Where(predicate);

        query = ascending 
            ? query.OrderBy(orderBy) 
            : query.OrderByDescending(orderBy);

        return await query.ToListAsync();
    }

    /// <summary>
    /// 获取前N条记录
    /// </summary>
    /// <param name="predicate">查询条件</param>
    /// <param name="count">获取的记录数</param>
    /// <returns>前N条记录</returns>
    public virtual async Task<IEnumerable<T>> GetTopAsync(Expression<Func<T, bool>> predicate, int count)
    {
        if (count <= 0)
            throw new ArgumentException("获取记录数必须大于0", nameof(count));

        return await _dbSet
            .Where(e => !e.IsDeleted)
            .Where(predicate)
            .Take(count)
            .ToListAsync();
    }

    /// <summary>
    /// 获取前N条记录并排序
    /// </summary>
    /// <typeparam name="TKey">排序字段类型</typeparam>
    /// <param name="predicate">查询条件</param>
    /// <param name="orderBy">排序表达式</param>
    /// <param name="count">获取的记录数</param>
    /// <param name="ascending">是否升序，默认true</param>
    /// <returns>排序后的前N条记录</returns>
    public virtual async Task<IEnumerable<T>> GetTopOrderedAsync<TKey>(
        Expression<Func<T, bool>> predicate,
        Expression<Func<T, TKey>> orderBy,
        int count,
        bool ascending = true)
    {
        if (count <= 0)
            throw new ArgumentException("获取记录数必须大于0", nameof(count));

        var query = _dbSet
            .Where(e => !e.IsDeleted)
            .Where(predicate);

        query = ascending 
            ? query.OrderBy(orderBy) 
            : query.OrderByDescending(orderBy);

        return await query.Take(count).ToListAsync();
    }

    // ============ 增加操作 ============
    
    /// <summary>
    /// 添加单个实体
    /// </summary>
    /// <param name="entity">要添加的实体</param>
    public virtual async Task AddAsync(T entity)
    {
        if (entity == null)
            throw new ArgumentNullException(nameof(entity));

        // 确保创建时间和更新时间被设置
        if (entity.CreatedAt == default)
            entity.CreatedAt = DateTime.UtcNow;
        if (entity.UpdatedAt == default)
            entity.UpdatedAt = DateTime.UtcNow;

        await _dbSet.AddAsync(entity);
    }

    /// <summary>
    /// 批量添加实体
    /// </summary>
    /// <param name="entities">要添加的实体集合</param>
    public virtual async Task AddRangeAsync(IEnumerable<T> entities)
    {
        if (entities == null)
            throw new ArgumentNullException(nameof(entities));

        var entityList = entities.ToList();
        if (!entityList.Any())
            return;

        // 确保所有实体的创建时间和更新时间被设置
        var now = DateTime.UtcNow;
        foreach (var entity in entityList)
        {
            if (entity.CreatedAt == default)
                entity.CreatedAt = now;
            if (entity.UpdatedAt == default)
                entity.UpdatedAt = now;
        }

        await _dbSet.AddRangeAsync(entityList);
    }

    // ============ 更新操作 ============
    
    /// <summary>
    /// 更新单个实体
    /// </summary>
    /// <param name="entity">要更新的实体</param>
    public virtual Task UpdateAsync(T entity)
    {
        if (entity == null)
            throw new ArgumentNullException(nameof(entity));

        // 更新时间戳
        entity.UpdatedAt = DateTime.UtcNow;

        _dbSet.Update(entity);
        return Task.CompletedTask;
    }

    /// <summary>
    /// 批量更新实体
    /// </summary>
    /// <param name="entities">要更新的实体集合</param>
    public virtual Task UpdateRangeAsync(IEnumerable<T> entities)
    {
        if (entities == null)
            throw new ArgumentNullException(nameof(entities));

        var entityList = entities.ToList();
        if (!entityList.Any())
            return Task.CompletedTask;

        // 更新时间戳
        var now = DateTime.UtcNow;
        foreach (var entity in entityList)
        {
            entity.UpdatedAt = now;
        }

        _dbSet.UpdateRange(entityList);
        return Task.CompletedTask;
    }

    // ============ 删除操作 ============
    
    /// <summary>
    /// 删除单个实体（软删除，设置IsDeleted=true）
    /// </summary>
    /// <param name="entity">要删除的实体</param>
    public virtual Task DeleteAsync(T entity)
    {
        if (entity == null)
            throw new ArgumentNullException(nameof(entity));

        // 直接设置BaseEntity属性，类型安全且高效
        entity.IsDeleted = true;
        entity.UpdatedAt = DateTime.UtcNow;

        _dbSet.Update(entity);
        return Task.CompletedTask;
    }

    /// <summary>
    /// 根据ID删除实体（软删除）
    /// </summary>
    /// <param name="id">实体ID</param>
    public virtual async Task DeleteAsync(Guid id)
    {
        var entity = await GetByIdAsync(id);
        if (entity != null)
        {
            await DeleteAsync(entity);
        }
    }

    /// <summary>
    /// 批量删除实体（软删除）
    /// </summary>
    /// <param name="entities">要删除的实体集合</param>
    public virtual Task DeleteRangeAsync(IEnumerable<T> entities)
    {
        if (entities == null)
            throw new ArgumentNullException(nameof(entities));

        var entityList = entities.ToList();
        if (!entityList.Any())
            return Task.CompletedTask;

        // 直接设置BaseEntity属性，类型安全且高效
        var now = DateTime.UtcNow;
        foreach (var entity in entityList)
        {
            entity.IsDeleted = true;
            entity.UpdatedAt = now;
        }

        _dbSet.UpdateRange(entityList);
        return Task.CompletedTask;
    }

    /// <summary>
    /// 根据条件批量删除实体（软删除）
    /// </summary>
    /// <param name="predicate">删除条件</param>
    public virtual async Task DeleteWhereAsync(Expression<Func<T, bool>> predicate)
    {
        var entities = await GetManyAsync(predicate);
        await DeleteRangeAsync(entities);
    }

    // ============ 工作单元操作 ============
    
    /// <summary>
    /// 保存所有更改到数据库
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>受影响的记录数</returns>
    public virtual async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        return await _context.SaveChangesAsync(cancellationToken);
    }

    // ============ 性能优化方法 ============

    /// <summary>
    /// 批量插入（高性能）- 适用于大量数据插入
    /// </summary>
    /// <param name="entities">要插入的实体集合</param>
    /// <param name="cancellationToken">取消令牌</param>
    public virtual async Task BulkInsertAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default)
    {
        if (entities == null)
            throw new ArgumentNullException(nameof(entities));

        var entityList = entities.ToList();
        if (!entityList.Any())
            return;

        // 确保时间戳
        var now = DateTime.UtcNow;
        foreach (var entity in entityList)
        {
            if (entity.CreatedAt == default)
                entity.CreatedAt = now;
            if (entity.UpdatedAt == default)
                entity.UpdatedAt = now;
        }

        // 使用EF Core的AddRange进行批量插入
        await _dbSet.AddRangeAsync(entityList, cancellationToken);
        await _context.SaveChangesAsync(cancellationToken);
    }

    /// <summary>
    /// 批量更新（高性能）- 适用于大量数据更新
    /// </summary>
    /// <param name="entities">要更新的实体集合</param>
    /// <param name="cancellationToken">取消令牌</param>
    public virtual async Task BulkUpdateAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default)
    {
        if (entities == null)
            throw new ArgumentNullException(nameof(entities));

        var entityList = entities.ToList();
        if (!entityList.Any())
            return;

        // 更新时间戳
        var now = DateTime.UtcNow;
        foreach (var entity in entityList)
        {
            entity.UpdatedAt = now;
        }

        _dbSet.UpdateRange(entityList);
        await _context.SaveChangesAsync(cancellationToken);
    }

    /// <summary>
    /// 批量软删除（高性能）- 直接执行SQL
    /// </summary>
    /// <param name="predicate">删除条件</param>
    /// <param name="cancellationToken">取消令牌</param>
    public virtual async Task BulkSoftDeleteAsync(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
    {
        var now = DateTime.UtcNow;
        
        // 使用ExecuteUpdateAsync进行批量更新（EF Core 7+的高性能方法）
        await _dbSet
            .Where(e => !e.IsDeleted)
            .Where(predicate)
            .ExecuteUpdateAsync(setters => setters
                .SetProperty(e => e.IsDeleted, true)
                .SetProperty(e => e.UpdatedAt, now), cancellationToken);
    }

    /// <summary>
    /// 检查连接是否可用
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    public virtual async Task<bool> IsHealthyAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            return await _context.Database.CanConnectAsync(cancellationToken);
        }
        catch
        {
            return false;
        }
    }
}
